package com.spzx.product.service.impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.nacos.common.utils.CollectionUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.spzx.common.core.utils.bean.BeanUtils;
import com.spzx.product.domain.Category;
import com.spzx.product.domain.vo.CategoryExcelVo;
import com.spzx.product.mapper.CategoryMapper;
import com.spzx.product.service.ICategoryService;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;

/**
 * 商品分类 Service 实现类
 *
 * @author Taeyang
 * @since 2025-04-17
 */
@Service
public class CategoryServiceImpl extends ServiceImpl<CategoryMapper, Category> implements ICategoryService {

    @Autowired
    private CategoryMapper categoryMapper;

    /**
     * 获取分类下拉树列表
     *
     * @param id 当前节点id
     * @return 结果集合
     */
    @Override
    public List<Category> treeSelect(Long id) {

        // 获取当前节点下的所有子节点
        List<Category> categorieList = baseMapper.selectList(new LambdaQueryWrapper<Category>().eq(Category::getParentId, id));

        // 判断当前节点是否有子节点
        if (CollectionUtils.isNotEmpty(categorieList)) {
            // 有子节点
            categorieList.forEach(category -> {
                // 查询子节点是否还有子节点
                Long count = baseMapper.selectCount(new LambdaQueryWrapper<Category>().eq(Category::getParentId, category.getId()));

                if (count > 0) {
                    // 节点还有子节点时，设置当前节点的字段为true
                    category.setHasChildren(true);
                } else {
                    // 节点没有子节点时，设置当前节点的字段为false
                    category.setHasChildren(false);
                }
            });
        }
        return categorieList;
    }

    /**
     * 根据分类id获取本级及全部上级节点id列表
     *
     * @param id 本级节点id
     * @return 本级及全部上级节点id列表
     */
    @Override
    public List<Long> getAllCategoryIdList(Long id) {
        // 创建返回列表
        List<Long> list = new ArrayList<>();

        // 调用本类私有方法查找指定分类id的父级分类
        List<Category> categoryList = getParentCategory(id, new ArrayList<>());

        // 循环查到的分类列表
        int size = categoryList.size();
        for (int i = size; i > 0; i--) {
            // 由尾至前，逆向保存分类对象的id到列表list（因为保存的时候分类对象是从小到大保存的）
            list.add(categoryList.get(i - 1).getId());
        }
        // 返回
        return list;
    }

    @Override
    public void importData(MultipartFile file) {
        // 使用EasyExcel解析数据
        try {
            List<CategoryExcelVo> categoryExcelVoList = EasyExcel.read(file.getInputStream()).head(CategoryExcelVo.class).sheet().doReadSync();
            if (!CollectionUtils.isEmpty(categoryExcelVoList)) {
                List<Category> categoryList = new ArrayList<>(categoryExcelVoList.size());
                for (CategoryExcelVo categoryExcelVo : categoryExcelVoList) {
                    Category category = new Category();
                    BeanUtils.copyProperties(categoryExcelVo, category, Category.class);
                    categoryList.add(category);
                }
                this.saveBatch(categoryList);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void exportData(HttpServletResponse response) {
        try {
            // 设置响应结果类型
            response.setContentType("application/vnd.ms-excel");
            response.setCharacterEncoding("utf-8");

            // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
            String fileName = URLEncoder.encode("分类数据", "UTF-8");
            response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
            response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");

            // 查询数据库中的数据
            List<Category> categoryList = categoryMapper.selectList(null);
            List<CategoryExcelVo> categoryExcelVoList = new ArrayList<>(categoryList.size());

            // 将从数据库中查询到的Category对象转换成CategoryExcelVo对象
            for (Category category : categoryList) {
                CategoryExcelVo categoryExcelVo = new CategoryExcelVo();
                BeanUtils.copyProperties(category, categoryExcelVo, CategoryExcelVo.class);
                categoryExcelVoList.add(categoryExcelVo);
            }

            // 写出数据到浏览器端
            EasyExcel.write(response.getOutputStream(), CategoryExcelVo.class).sheet("分类数据").doWrite(categoryExcelVoList);

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 根据分类id获取当前分类及本分类的所有父级分类合集列表
     *
     * @param id           当前分类
     * @param categoryList 列表
     * @return id > 0 时一直递归寻找父级，= 0 时 跳出递归返回数据
     */
    private List<Category> getParentCategory(Long id, List<Category> categoryList) {

        // id > 0 时一直递归寻找父级，= 0 时 跳出递归返回数据
        while (id > 0) {
            // 根据id查询唯一的分类对象并只保留id和父级id
            // baseMapper.selectOne(...)：执行查询并期望返回唯一结果。若找到多条记录会抛出异常，未找到则返回 null。
            // eq(Category::getId, id)：筛选条件为 id = 指定值
            // select(Category::getId, Category::getParentId)：仅查询 id 和 parent_id 两个字段，不返回其他字段（如名称、描述等）。
            Category category = baseMapper.selectOne(new LambdaQueryWrapper<Category>().eq(Category::getId, id).select(Category::getId, Category::getParentId));

            // 将查询到的分类对象信息保存到列表种
            categoryList.add(category);

            // 递归调用，根据刚刚查询到的分类对象的父级id去递归查找分类对象的父级，并依次保存到列表中
            return getParentCategory(category.getParentId(), categoryList);
        }
        // 直至父级id = 0（不存在小于0的情况，但是可能存在null，说明数据库表有问题）
        return categoryList;
    }
}
